/*
    libhdvbd - Library for building sophisticated DVB applications
    Copyright (C) 2012 Tony Houghton <h@realh.co.uk>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser general Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser general Public License for more details.

    You should have received a copy of the GNU Lesser general Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <glib.h>

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "dbcommon.h"
#include "i18n.h"

void
hdvb_db_complain(sqlite3 *sql, int code, const char *format, ...)
{
    va_list ap;
    
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
    fprintf(stderr, ":\nsqlite result code %d: %s\n", code,
            sql ? sqlite3_errmsg(sql) : _("unknown reason"));
}

sqlite3_stmt *
hdvb_db_prepare_statement(sqlite3 *sql, const char *statement)
{
    sqlite3_stmt *stmt = NULL;
    int result = sqlite3_prepare_v2(sql, statement, -1, &stmt, NULL);
            
    if (result)
    {
        hdvb_db_complain(sql, result, _("Unable to prepare SQL statement '%s'"),
                statement);
        if (stmt)
            sqlite3_finalize(stmt);
        return NULL;
    }
    return stmt;
}

sqlite3 *
hdvb_db_open(const char *filename, int version,
        void (*creator)(sqlite3 *sql, gpointer handle), gpointer handle)
{
    sqlite3 *sql = NULL;
    gboolean ram = !strcmp(filename, ":memory:");
    gboolean create = (ram || !g_file_test(filename, G_FILE_TEST_EXISTS)) &&
            creator;
    int result = sqlite3_open_v2(filename, &sql,
            SQLITE_OPEN_READWRITE |
            (create ? SQLITE_OPEN_CREATE : 0), NULL);
    
    if (result)
    {
        if (creator)
        {
            hdvb_db_complain(sql, result, _("Unable to open database '%s'"),
                    filename);
        }
        if (sql)
            sqlite3_close(sql);
        return NULL;
    }
    if (create)
    {
        if (creator)
        {
            char *s = g_strdup_printf(
                    "INSERT INTO version (version) VALUES (%d);",
                    version);
                    
            hdvb_db_exec(sql, "DROP TABLE IF EXISTS version; "
                    "CREATE TABLE version (version INT NOT NULL);");
            hdvb_db_exec(sql, s);
            creator(sql, handle);
            g_free(s);
        }
    }
    else if (!ram)
    {
        sqlite3_stmt *stmt = 
                hdvb_db_prepare_statement(sql, "SELECT version FROM version");
        
        if (!stmt)
        {
            g_critical(_("Error was in database '%s'"), filename);
            sqlite3_close(sql);
            return NULL;
        }
        result = sqlite3_step(stmt);
        if (result != SQLITE_ROW)
        {
            hdvb_db_complain(sql, result,
                    _("Unable to read version from database '%s'"),
                    filename);
            sqlite3_finalize(stmt);
            sqlite3_close(sql);
            return NULL;
        }
        result = sqlite3_column_int(stmt, 0);
        if (result != version)
        {
            fprintf(stderr, 
                    _("Database '%s' has incorrect version %d, expected %d\n"),
                    filename, result, version);
            sqlite3_finalize(stmt);
            sqlite3_close(sql);
            return NULL;
        }
    }
    return sql;
}

gboolean
hdvb_db_exec(sqlite3 *sql, const char *statement)
{
    char *errmsg = NULL;
    int result = sqlite3_exec(sql, statement, NULL, NULL, &errmsg);
    
    if (result != SQLITE_OK && result != SQLITE_DONE)
    {
        g_warning(_("Error %d executing SQL '%s': %s"),
                result, statement, errmsg);
    }
    else if (errmsg)
    {
        g_warning(_("Successful result code but "
                "error message executing SQL '%s': %s"),
                statement, errmsg);
    }
    if (errmsg)
        sqlite3_free(errmsg);
    return (result == SQLITE_OK || result == SQLITE_DONE);
}

int
hdvb_db_step(sqlite3_stmt *stmt)
{
    int result = sqlite3_step(stmt);
    
    if (result != SQLITE_OK && result != SQLITE_DONE && result != SQLITE_ROW)
    {
        g_warning(_("Error %d executing SQL query: %s"), result,
                sqlite3_errmsg(sqlite3_db_handle(stmt)));
    }
    return result;
}
